#include <vector>
#include <queue>
#include "sched_rr2.h"
#include "basesched.h"
#include <iostream>

using namespace std;

SchedRR2::SchedRR2(vector<int> argn) {
	// Round robin recibe la cantidad de cores y sus cpu_quantum por parámetro
	for(int i = 1; i <= argn[0]; ++i) {
		quantum.push_back(argn[i]);
		quantumRestante.push_back(argn[i]);
		taskQueuesByCore.push_back(queue<int>());
		blockedTasksByCore.push_back(0);
	}
}

SchedRR2::~SchedRR2() {

}

void SchedRR2::load(int pid) {
	unsigned int min = taskQueuesByCore[0].size();
	unsigned int minPos = 0;
	for(int i = 1; i < (int) taskQueuesByCore.size(); ++i) {
		if((taskQueuesByCore[i].size() + blockedTasksByCore[i]) < min) {
			min = taskQueuesByCore[i].size() + blockedTasksByCore[i];
			minPos = i;
		}
	}
	taskQueuesByCore[minPos].push(pid);
}

void SchedRR2::unblock(int pid) {
	taskQueuesByCore[blockedTasks[pid]].push(pid);
	blockedTasksByCore[blockedTasks[pid]]--;
}

int SchedRR2::tick(int cpu, const enum Motivo m) {
	int taskToExecute = IDLE_TASK;
	if(m == EXIT) {
		taskQueuesByCore[cpu].pop();
		if(!taskQueuesByCore[cpu].empty()) {
			taskToExecute = taskQueuesByCore[cpu].front();
		}
		quantumRestante[cpu] = quantum[cpu];
	} else if(m == TICK) {
		if(quantumRestante[cpu] == 0) {
			if(!taskQueuesByCore[cpu].empty()) {
				int previousTask = taskQueuesByCore[cpu].front();
				taskQueuesByCore[cpu].pop();
				taskQueuesByCore[cpu].push(previousTask);
				taskToExecute = taskQueuesByCore[cpu].front();
				quantumRestante[cpu] = quantum[cpu];
			}
		} else if(current_pid(cpu) == IDLE_TASK && !taskQueuesByCore[cpu].empty()) {
			taskToExecute = taskQueuesByCore[cpu].front();
			quantumRestante[cpu] = quantum[cpu];
		} else {
			quantumRestante[cpu]--;
			taskToExecute = current_pid(cpu);
		}
	} else { // m = BLOCK
		blockedTasks[current_pid(cpu)] = cpu;
		++blockedTasksByCore[cpu];
		taskQueuesByCore[cpu].pop();
		if(!taskQueuesByCore[cpu].empty()) {
			taskToExecute = taskQueuesByCore[cpu].front();
		}
	}
	return taskToExecute;
}

int SchedRR2::next(int cpu) {
	return 0;
}
